home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
151-175
/
scopedisk156
/
mwtapebackup
/
tapedev.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-19
|
16KB
|
556 lines
/*
* tapedev.c - by Markus Wandel - 1990
* Placed in the public domain 7 Oct 1990
* Please have the courtesy to give credit
* if you use this code in any program.
*
*/
#include <exec/ports.h>
#include <exec/io.h>
#include <devices/scsidisk.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/filehandler.h>
#define CLOSED 0
#define JUST_OPENED 1
#define OPEN_FOR_READ 2
#define OPEN_FOR_WRITE 3
#define SCSI_OK 0
#define SCSI_ERROR 1
#define SCSI_UNIT_ATTENTION 2
#define SCSI_FILEMARK 3
#define UNKNOWN 0
#define REWOUND 1
#define IN_FILE 2
#define AT_FILEMARK 3
#define AT_END 4
#define ACT_FINDINPUT 1005
#define ACT_FINDOUTPUT 1006
#define ACT_END 1007
extern void *FindTask();
extern struct DosPacket *taskwait();
extern struct MsgPort *CreatePort();
extern struct IOStdReq *CreateStdIO();
extern long OpenDevice();
extern void *OpenLibrary();
extern int AutoAutoRequest();
extern void *malloc();
unsigned long buffer_size;
unsigned long buffer_cutoff;
long unitnum;
long flags;
char *devname;
int devlength;
struct MsgPort *mp;
struct IOStdReq *iob;
struct Process *myproc;
int tapestate;
int errnum;
ULONG buffer_highmark;
ULONG buffer_current;
int read_eof;
struct SCSICmd cmd;
ULONG actual;
void *IntuitionBase;
int notified;
UBYTE sense_cmd[] = { 3,0,0,0,20,0 };
UBYTE rewind_cmd[] = { 1,0,0,0,0,0 };
UBYTE test_ready_cmd[] = { 0,0,0,0,0,0 };
UBYTE skip_filemark_cmd[] = { 0x11,1,0,0,1,0 };
UBYTE skip_end_cmd[] = {0x11,3,0,0,1,0 };
UBYTE write_filemark_cmd[] = {0x10,0,0,0,1,0};
UBYTE mode_sense_cmd[] = {0x1a,0,0,0,3,0};
UBYTE *buffer;
UBYTE sensebuf[20];
_main()
{
register struct DosPacket *pkt;
struct DeviceNode *devnode;
register int openstate;
UBYTE *ptr;
int i;
long error;
myproc = (struct Process *)FindTask(0L);
pkt = taskwait(myproc);
devnode = (struct DeviceNode *) ((pkt->dp_Arg3)<<2);
if(parsestartup((pkt->dp_Arg2)<<2) || buffer_size < 10) {
returnpkt(pkt,myproc,DOSFALSE,ERROR_NO_FREE_STORE);
return 0;
}
buffer_cutoff = buffer_size << 8;
buffer_size <<= 9;
buffer = (UBYTE *)malloc(buffer_size);
if(!buffer) {
returnpkt(pkt,myproc,DOSFALSE,ERROR_NO_FREE_STORE);
return 0;
}
IntuitionBase = OpenLibrary("intuition.library",0L);
if(!IntuitionBase) {
returnpkt(pkt,myproc,DOSFALSE,ERROR_NO_FREE_STORE);
free(buffer);
return 0;
}
mp = CreatePort(0L,0L);
if(!mp) {
returnpkt(pkt,myproc,DOSFALSE,ERROR_NO_FREE_STORE);
CloseLibrary(IntuitionBase);
free(buffer);
return 0;
}
iob = CreateStdIO(mp);
if(!iob) {
CloseLibrary(IntuitionBase);
free(buffer);
DeletePort(mp);
returnpkt(pkt,myproc,DOSFALSE,ERROR_NO_FREE_STORE);
return 0;
}
devname[devlength] = 0;
error = OpenDevice(devname,unitnum,iob,flags);
devname[devlength] = '/';
if(error) {
CloseLibrary(IntuitionBase);
free(buffer);
DeleteStdIO(iob);
DeletePort(mp);
returnpkt(pkt,myproc,DOSFALSE,ERROR_OBJECT_NOT_FOUND);
return 0;
}
devnode->dn_Task = &myproc->pr_MsgPort;
returnpkt(pkt,myproc,DOSTRUE,0L);
openstate = CLOSED;
tapestate = UNKNOWN;
for(;;) {
pkt = taskwait(myproc);
switch(pkt->dp_Type) {
case ACT_FINDINPUT:
case ACT_FINDOUTPUT:
if(openstate != CLOSED) returnpkt(pkt,myproc,DOSFALSE,
ERROR_OBJECT_IN_USE);
else if(not_ready()) {
returnpkt(pkt,myproc,DOSFALSE,ERROR_OBJECT_NOT_FOUND);
} else {
errnum = 0;
notified = 0;
openstate = JUST_OPENED;
ptr = (UBYTE *) ((pkt->dp_Arg3)<<2);
for(i=*ptr++;i>1;i--) {
if(*ptr++ == ':') {
if(*ptr == 'R' || *ptr == 'r')
rewind();
else if(*ptr == 'A' || *ptr == 'a')
append();
i=0;
}
}
if(tapestate == UNKNOWN) rewind();
returnpkt(pkt,myproc,DOSTRUE,0L);
}
break;
case ACTION_READ:
switch(openstate) {
case JUST_OPENED:
init_read();
openstate = OPEN_FOR_READ;
case OPEN_FOR_READ:
tape_read(pkt);
break;
default:
returnpkt(pkt,myproc,-1L,ERROR_READ_PROTECTED);
}
break;
case ACTION_WRITE:
switch(openstate) {
case JUST_OPENED:
init_write();
openstate = OPEN_FOR_WRITE;
case OPEN_FOR_WRITE:
tape_write(pkt);
break;
default:
returnpkt(pkt,myproc,-1L,ERROR_OBJECT_NOT_FOUND);
}
break;
case ACT_END:
if(openstate == OPEN_FOR_WRITE) finish_write();
openstate = CLOSED;
returnpkt(pkt,myproc,DOSTRUE,0L);
break;
default:
returnpkt(pkt,myproc,DOSFALSE,(long)ERROR_ACTION_NOT_KNOWN);
}
}
}
/*
* This function is called for every open and tests if a tape is ready.
*
* tapestate becomes UNKNOWN if no tape is ready.
*
*/
not_ready()
{
do {
switch(doscsi(0L,test_ready_cmd,0L,6,1)) {
case SCSI_OK:
return 0;
case SCSI_UNIT_ATTENTION:
if(doscsi(0L,test_ready_cmd,0L,6,1)==SCSI_OK) return 0;
default:
tapestate = UNKNOWN;
}
} while(AutoAutoRequest("Tape unit not ready.",0L,0L,"Retry","Cancel"));
return -1;
}
rewind()
{
if(doscsi(0L,rewind_cmd,0L,6,1))
errnum = ERROR_OBJECT_NOT_FOUND;
else tapestate = REWOUND;
}
append()
{
if(doscsi(0L,skip_end_cmd,0L,6,1))
errnum = ERROR_OBJECT_NOT_FOUND;
else tapestate = AT_END;
}
init_read()
{
int i;
buffer_current = 0;
buffer_highmark = 0;
read_eof = 0;
if(!errnum) switch(tapestate) {
case IN_FILE:
if(doscsi(0L,skip_filemark_cmd,0L,6,1)) {
tapestate = UNKNOWN;
errnum = ERROR_OBJECT_NOT_FOUND;
}
tapestate = AT_FILEMARK;
case AT_FILEMARK:
case REWOUND:
break;
default:
errnum = ERROR_OBJECT_NOT_FOUND;
}
}
init_write()
{
UBYTE msbuf[3];
buffer_current = 0;
if(!errnum) switch(tapestate) {
case AT_FILEMARK:
case IN_FILE:
if(doscsi(0L,skip_end_cmd,0L,6,1)) {
errnum = ERROR_OBJECT_NOT_FOUND;
tapestate = UNKNOWN;
}
case AT_END:
case REWOUND:
if(doscsi(msbuf,mode_sense_cmd,3L,6,1)) {
errnum = ERROR_OBJECT_NOT_FOUND;
return;
}
if(msbuf[2] & 0x80) {
errnum = ERROR_OBJECT_NOT_FOUND;
AutoAutoRequest("Tape is write protected.",0L,0L,0L,"Abort");
notified = 1;
return;
}
break;
default:
errnum = ERROR_OBJECT_NOT_FOUND;
}
}
char readerr1[] = "An error has occurred while";
char readerr2[] = "trying to read from the tape.";
tape_read(pkt)
register struct DosPacket *pkt;
{
register UBYTE *ptr = (UBYTE *)pkt->dp_Arg2;
register ULONG length = pkt->dp_Arg3;
register ULONG fragment;
UBYTE cmdbuf[6];
if(errnum) {
if(!notified) {
AutoAutoRequest(readerr1,readerr2,0L,0L," OK ");
notified = 1;
}
returnpkt(pkt,myproc,-1L,(long)errnum);
return;
}
/*
* First, transfer whatever is left in the buffer.
*/
if(buffer_current < buffer_highmark ) {
fragment = buffer_highmark - buffer_current;
if(length<fragment) fragment = length;
CopyMem(buffer+buffer_current,ptr,fragment);
length -= fragment;
buffer_current += fragment;
ptr += fragment;
}
if(!read_eof) {
if(length>buffer_cutoff) {
fragment = length & ~511;
cmdbuf[0] = 8;
cmdbuf[1] = 1;
*((ULONG *)&cmdbuf[2]) = fragment>>1;
switch(doscsi(ptr,cmdbuf,fragment,6,1)) {
case SCSI_FILEMARK:
fragment = actual;
read_eof = 1;
break;
case SCSI_OK:
tapestate = IN_FILE;
break;
default:
read_eof = 1;
fragment = 0;
AutoAutoRequest(readerr1,readerr2,0L,0L," OK ");
notified = 1;
break;
}
ptr += fragment;
length -= fragment;
}
if(length && !read_eof) {
cmdbuf[0] = 8;
cmdbuf[1] = 1;
*((ULONG *)&cmdbuf[2]) = buffer_size>>1;
switch(doscsi(buffer,cmdbuf,(long)buffer_size,6,1)) {
case SCSI_FILEMARK:
read_eof = 1;
buffer_highmark = actual;
break;
case SCSI_OK:
buffer_highmark = actual;
tapestate = IN_FILE;
break;
default:
read_eof = 1;
buffer_highmark = 0;
AutoAutoRequest(readerr1,readerr2,0L,0L," OK ");
notified = 1;
errnum = ERROR_SEEK_ERROR;
}
buffer_current = length;
if(buffer_highmark < buffer_current) buffer_current = buffer_highmark;
CopyMem(buffer,ptr,buffer_current);
length -= buffer_current;
}
}
if(errnum) if(pkt->dp_Arg3==length) {
returnpkt(pkt,myproc,-1L,ERROR_SEEK_ERROR);
return;
}
returnpkt(pkt,myproc,pkt->dp_Arg3-length,0L);
}
char writerr1[] = "An error has occurred while";
char writerr2[] = "trying to write to the tape.";
char writerr3[] = "Tape data is probably invalid.";
tape_write(pkt)
register struct DosPacket *pkt;
{
register UBYTE *ptr = (UBYTE *)pkt->dp_Arg2;
register ULONG length = pkt->dp_Arg3;
register ULONG fragment;
UBYTE cmdbuf[6];
if(errnum) {
if(!notified) {
AutoAutoRequest(writerr1,writerr2,writerr3,0L," OK ");
notified = 1;
}
returnpkt(pkt,myproc,-1L,(long)errnum);
return;
}
if(buffer_current || (length <= buffer_cutoff)) {
fragment = buffer_size - buffer_current;
if(length < fragment) fragment = length;
CopyMem(ptr,buffer+buffer_current,fragment);
ptr += fragment;
buffer_current += fragment;
length -= fragment;
/*
* If the buffer is full, flush it.
*
*/
if(buffer_current == buffer_size) {
cmdbuf[0] = 10;
cmdbuf[1] = 1;
*((ULONG *)&cmdbuf[2]) = buffer_size>>1;
if(doscsi(buffer,cmdbuf,(long)buffer_size,6,0)) {
AutoAutoRequest(writerr1,writerr2,writerr3,0L," OK ");
notified = 1;
errnum = ERROR_SEEK_ERROR;
}
buffer_current = 0;
}
}
if(!errnum) {
if(length>buffer_cutoff) {
fragment = length & ~511;
cmdbuf[0] = 10;
cmdbuf[1] = 1;
*((ULONG *)&cmdbuf[2]) = fragment>>1;
if(doscsi(ptr,cmdbuf,fragment,6,0)) {
AutoAutoRequest(writerr1,writerr2,writerr3,0L," OK ");
notified = 1;
errnum = ERROR_SEEK_ERROR;
}
length -= fragment;
ptr += fragment;
}
if(length && !errnum) {
CopyMem(ptr,buffer,length);
buffer_current = length;
length = 0;
}
}
if(errnum)
returnpkt(pkt,myproc,-1L,ERROR_SEEK_ERROR);
else
returnpkt(pkt,myproc,pkt->dp_Arg3,0L);
}
finish_write()
{
UBYTE cmdbuf[6];
ULONG fragment;
if(buffer_current && !errnum) {
fragment = (buffer_current + 511) & ~511;
while(buffer_current < fragment) buffer[buffer_current++] = 0;
cmdbuf[0] = 10;
cmdbuf[1] = 1;
*((ULONG *)&cmdbuf[2]) = fragment>>1;
if(doscsi(buffer,cmdbuf,fragment,6,0))
AutoAutoRequest(writerr1,writerr2,writerr3,0L," OK ");
notified = 1;
}
if(doscsi(0L,write_filemark_cmd,0L,6,1)) {
if(!notified) AutoAutoRequest(writerr1,writerr2,writerr3,0L," OK ");
} else
tapestate = AT_END;
}
int doscsi(buf,cmdbuf,length,cmdlength,flags)
UWORD *buf;
UBYTE *cmdbuf;
ULONG length;
int cmdlength,flags;
{
cmd.scsi_Data = buf;
cmd.scsi_Length = length;
cmd.scsi_CmdLength = cmdlength;
cmd.scsi_Flags = flags;
cmd.scsi_Command = cmdbuf;
iob->io_Command = 28;
iob->io_Data = (APTR) &cmd;
iob->io_Length = sizeof(cmd);
DoIO(iob);
actual = cmd.scsi_Actual;
switch(iob->io_Error) {
case 0:
if(length == actual) return SCSI_OK;
else return SCSI_ERROR;
case HFERR_BadStatus:
cmd.scsi_Command = sense_cmd;
cmd.scsi_Flags = 1;
cmd.scsi_CmdLength = 6;
cmd.scsi_Length = 20;
cmd.scsi_Data = (UWORD *) sensebuf;
DoIO(iob);
if(iob->io_Error) return SCSI_ERROR;
if(cmd.scsi_Actual > 4) {
if(sensebuf[2] == 1 && actual == length) {
return SCSI_OK;
}
if(sensebuf[2] == 6) {
tapestate = UNKNOWN;
return SCSI_UNIT_ATTENTION;
}
if(sensebuf[2] == 8) {
tapestate = AT_END;
return SCSI_ERROR;
}
if(sensebuf[2] == 0x80) {
tapestate = AT_FILEMARK;
return SCSI_FILEMARK;
}
}
default:
tapestate = UNKNOWN;
return SCSI_ERROR;
}
}
int parsestartup(msg)
register char *msg;
{
register int i,state = 0;
buffer_size = 0;
unitnum = 0;
flags = 0 ;
if(!msg) return 1;
for(i=1;i<=msg[0];i++) {
if(msg[i] == '/') {
switch(++state) {
case 1: devname = &msg[i+1];
break;
case 2: devlength = (&msg[i]) - devname;
break;
case 4:
return 1;
}
} else if(state != 1) {
if(msg[i] < '0' || msg[i] > '9') return 1;
switch(state) {
case 0: buffer_size = 10 * buffer_size + msg[i] - '0';
break;
case 2: unitnum = 10 * unitnum + msg[i] - '0';
break;
case 3: flags = 10 * flags + msg[i] - '0';
}
}
}
return (state<3);
}